package controller

import (
	"fmt"
	"mpps/tools/auth"
	common "mpps/tools/common"
	"mpps/tools/config"
	"mpps/web/models"
	"os"
	"path"
	"path/filepath"
	"strconv"

	ProgramDownload "mpps/services/srv-ProgramDownload/proto"
	ProgramLatest "mpps/services/srv-ProgramLatest/proto"
	ProgramList "mpps/services/srv-ProgramList/proto"
	ProgramRollback "mpps/services/srv-ProgramRollback/proto"
	ProgramUpload "mpps/services/srv-ProgramUpload/proto"

	"github.com/asim/go-micro/v3/logger"
	"github.com/gin-gonic/gin"
)

type ProgramController interface {
	ProgramUpload(c *gin.Context)
	ProgramDownload(c *gin.Context)
	ProgramList(c *gin.Context)
	ProgramRollback(c *gin.Context)
	ProgramLatest(c *gin.Context)
}

type Program struct {
	ProgramController
	ProgramDownloadService ProgramDownload.ProgramDownloadService
	ProgramUploadService   ProgramUpload.ProgramUploadService
	ProgramListService     ProgramList.ProgramListService
	ProgramRollbackService ProgramRollback.ProgramRollbackService
	ProgramLatestService   ProgramLatest.ProgramLatestService
}

func NewProgramController() ProgramController {
	return &Program{
		ProgramDownloadService: ProgramDownload.NewProgramDownloadService(config.ProgramDownloadSrv, common.GetMicroClient()),
		ProgramUploadService:   ProgramUpload.NewProgramUploadService(config.ProgramUploadSrv, common.GetMicroClient()),
		ProgramListService:     ProgramList.NewProgramListService(config.ProgramListSrv, common.GetMicroClient()),
		ProgramRollbackService: ProgramRollback.NewProgramRollbackService(config.ProgramRollbackSrv, common.GetMicroClient()),
		ProgramLatestService:   ProgramLatest.NewProgramLatestService(config.ProgramLatestSrv, common.GetMicroClient()),
	}
}

// @Summary 	上传小程序、jsCore zip包
// @Description 上传小程序、jsCore zip包
// @Tags 		小程序
// @Accept 		multipart/form-data
// @Param       token       	header      string  true  	"token"
// @Param       programId		formData	string	false	"小程序id"
// @Param       mode			formData	string	true 	"小程序/js类型dev、preview、prod"	Enums(dev, preview, prod)
// @Param       fileType		formData	string	true 	"文件类型program、js"	Enums(program, js)
// @Param       version			formData	string	true 	"version"
// @Param       file  			formData	file  	true  	"小程序、jsCore zip包"
// @Success 	200 {object} models.Resp
// @Failure 	500 {object} models.Resp
// @Router 		/v1/program/upload [post]
func (m *Program) ProgramUpload(c *gin.Context) {
	programId := c.PostForm("programId")
	mode := c.PostForm("mode")
	fileType := c.PostForm("fileType")
	version := c.PostForm("version")
	f, err := c.FormFile("file")
	if err != nil {
		models.WriteHttpFail(c, common.ErrParamsValidation)
		return
	}
	pbRsp, err := m.ProgramUploadService.Call(auth.WithToken(c), &ProgramUpload.Request{
		ProgramId: programId,
		Mode:      mode,
		FileType:  fileType,
		FileName:  f.Filename,
		Version:   version,
	})
	if err != nil {
		models.WriteHttpFail(c, common.ErrParamsUpload)
		return
	} else {
		pathFile := fmt.Sprintf("./program/%s", pbRsp.FileId)
		err := common.CreateDir(pathFile)
		if err != nil {
			models.WriteHttpFail(c, common.ErrParamsUpload)
			return
		}
		dst := path.Join(pathFile, "dist.zip")
		err = c.SaveUploadedFile(f, dst)
		if err != nil {
			models.WriteHttpFail(c, common.ErrParamsUpload)
			return
		}
		models.WriteHttpCodeSucc(c, common.OK)
	}
}

// @Summary 	下载小程序、jsCore zip包
// @Description 下载小程序、jsCore zip包
// @Tags 		小程序
// @Accept 		json
// @Param 		programId	query	string	false	"小程序id"
// @Param       mode		query	string	true 	"小程序/js类型dev、preview、prod"	Enums(dev, preview, prod)
// @Param 		fileType 	query	string	true 	"文件类型program、js"	Enums(program, js)
// @Param 		version 	query	string	true 	"version"
// @Success 	200 {object} models.Resp
// @Failure 	500 {object} models.Resp
// @Router 		/v1/program/download [get]
func (m *Program) ProgramDownload(c *gin.Context) {
	programId := c.Query("programId")
	mode := c.Query("mode")
	fileType := c.Query("fileType")
	version := c.Query("version")
	pbRsp, err := m.ProgramDownloadService.Call(auth.WithToken(c), &ProgramDownload.Request{
		ProgramId: programId,
		Mode:      mode,
		FileType:  fileType,
		Version:   version,
	})
	if err != nil {
		logger.Info(err)
		models.WriteHttpFail(c, common.ErrDatabasequery)
		return
	}
	if len(pbRsp.FileId) > 0 {
		pathFile := fmt.Sprintf("./program/%s/dist.zip", pbRsp.FileId)
		logger.Info(pathFile)
		if _, err := os.Stat(pathFile); err != nil {
			models.WriteHttpFail(c, common.ErrResources)
			return
		}
		_, filename := filepath.Split(pathFile)
		c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
		c.Header("Content-Type", "application/octet-stream")
		c.Header("Content-Transfer-Encoding", "binary")
		c.Header("Cache-Control", "no-cache")
		c.File(pathFile)
		return
	}
	models.WriteHttpFail(c, common.ErrParamsDownload)
}

// @Summary 	获取小程序、jsCore记录列表
// @Description 获取小程序、jsCore记录列表
// @Tags 		小程序
// @Accept 		json
// @Param       token      	header  string  true  	"token"
// @Param 		programId	query	string	false	"小程序id"
// @Param       mode		query	string	true 	"小程序/js类型dev、preview、prod"	Enums(dev, preview, prod)
// @Param 		fileType 	query	string	true 	"文件类型program、js"	Enums(program, js)
// @Param 		currPage 	query	int		true 	"第几页"
// @Param 		pageSize 	query	int		true 	"每页条数"
// @Success 	200 {object} models.Resp
// @Failure 	500 {object} models.Resp
// @Router 		/v1/program/list [get]
func (m *Program) ProgramList(c *gin.Context) {
	programId := c.Query("programId")
	mode := c.Query("mode")
	fileType := c.Query("fileType")
	currPage, _ := strconv.Atoi(c.DefaultQuery("currPage", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "20"))
	pbRsp, err := m.ProgramListService.Call(auth.WithToken(c), &ProgramList.Request{
		ProgramId: programId,
		Mode:      mode,
		FileType:  fileType,
		CurrPage:  int32(currPage),
		PageSize:  int32(pageSize),
	})
	if err != nil {
		logger.Info(err)
		models.WriteHttpFail(c, common.ErrGetList)
		return
	}
	models.WriteHttpSucc(c, pbRsp)
}

// @Summary 	回滚小程序、jsCore到上一个版本
// @Description 回滚小程序、jsCore到上一个版本
// @Tags 		小程序
// @Accept 		json
// @Param       token		header     string  				true  	"token"
// @Param 		body参数	body 		models.RollbackReq	true 	"请求body"
// @Success 	200 {object} models.Resp
// @Failure 	500 {object} models.Resp
// @Router 		/v1/program/rollback [post]
func (m *Program) ProgramRollback(c *gin.Context) {
	body := models.RollbackReq{}
	err := c.BindJSON(&body)
	if err != nil {
		models.WriteHttpFail(c, common.ErrParamsValidation)
		return
	}
	if len(body.Mode) <= 0 || len(body.FileType) <= 0 {
		models.WriteHttpFail(c, common.ErrParamsValidation)
		return
	}
	pbRsp, err := m.ProgramRollbackService.Call(auth.WithToken(c), &ProgramRollback.Request{
		ProgramId: body.ProgramId,
		Mode:      body.Mode,
		FileType:  body.FileType,
	})
	if err != nil {
		logger.Info(err)
		models.WriteHttpFail(c, common.ErrPostRollback)
		return
	}
	models.WriteHttpSucc(c, pbRsp)
}

// @Summary 	获取小程序、jsCore 最新版本
// @Description 获取小程序、jsCore 最新版本
// @Tags 		小程序
// @Accept 		json
// @Param 		programId	query	string	false	"小程序id"
// @Param       mode		query	string	true 	"小程序/js类型dev、preview、prod"	Enums(dev, preview, prod)
// @Param 		fileType 	query	string	true 	"文件类型program、js"	Enums(program, js)
// @Success 	200 {object} models.Resp
// @Failure 	500 {object} models.Resp
// @Router 		/v1/program/latest [get]
func (m *Program) ProgramLatest(c *gin.Context) {
	programId := c.Query("programId")
	mode := c.Query("mode")
	fileType := c.Query("fileType")
	pbRsp, err := m.ProgramLatestService.Call(auth.WithToken(c), &ProgramLatest.Request{
		ProgramId: programId,
		Mode:      mode,
		FileType:  fileType,
	})
	if err != nil {
		logger.Info(err)
		models.WriteHttpFail(c, common.ErrGetLatest)
		return
	}
	models.WriteHttpSucc(c, pbRsp)
}
